﻿using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;

public class XEditorFBXPostprocessor : AssetPostprocessor
{
    public enum FbxLoopAnimation{
        Idle,
        Run,
        Walk,
        Forward,
        Backward,
        Stun,
        Work,
    };

    static bool IsLoopAnimation(string name)
    {
        string[] arrayName = System.Enum.GetNames(typeof(FbxLoopAnimation));
        foreach(string typeName in arrayName)
        {
            if (typeName == name)
            {
                return true;
            }
        }

        return false;
    }

    static Object GeneratePrefab(GameObject go, string path, string name)
    {
        string fullpath = path + "/" + name + ".prefab";

        GameObject prefab = PrefabUtility.SaveAsPrefabAsset(go, fullpath);
        GameObject.DestroyImmediate(go);

        Debug.Log("fbx postprocess auto generate prefab : <color=red>" + fullpath + "</color>");

        return prefab;
    }

    IEnumerator OnGenerateModelPrefab(GameObject go, ModelImporterAnimationType importAnimationType, bool useMeshCollider=false, bool copyToResources=false)
    {
        string name = Path.GetFileNameWithoutExtension(assetPath);
        yield return null;

        GameObject loadGo = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
        if (!loadGo)
            throw new System.ArgumentNullException(assetPath);

        GameObject prefab = new GameObject(name);
        if (!prefab)
            throw new System.NullReferenceException();

        if (useMeshCollider)
        {
            prefab.AddComponent<MeshCollider>();
        }
        else
        {
            CapsuleCollider collider = prefab.AddComponent<CapsuleCollider>();
            collider.center = new Vector3(0, 1, 0);
            collider.height = 2f;
        }


        GameObject rendererGo = GameObject.Instantiate(loadGo);
        rendererGo.name = typeof(Renderer).Name;
        rendererGo.transform.SetParent(prefab.transform, false);
        rendererGo.transform.localScale         = Vector3.one;
        rendererGo.transform.localPosition      = Vector3.zero;
        rendererGo.transform.localEulerAngles   = Vector3.zero;

        MeshRenderer[] meshRenderers = rendererGo.GetComponentsInChildren<MeshRenderer>();
        if (meshRenderers.Length > 0)
        {
            Animator emptyAnimator = rendererGo.GetComponent<Animator>();
            if (emptyAnimator)
            {
                GameObject.DestroyImmediate(emptyAnimator);
            }
        }
     
        string outpath = Path.GetDirectoryName(assetPath);
        if (copyToResources)
        {
            outpath = outpath.Replace(XDirectory.Art.ToString(), XDirectory.Resources.ToString());
        }

        if (!Directory.Exists(outpath))
        {
            Directory.CreateDirectory(outpath);
        }

        GeneratePrefab(prefab, outpath, name);
    }

    bool PostprocessModels(GameObject go, ModelImporterAnimationType importAnimationType, bool useMeshCollider = false, bool copyToResources=false)
    {
        ModelImporter mi = (ModelImporter)assetImporter;
        if (assetPath.Contains("@"))
        {
            foreach (SkinnedMeshRenderer smr in go.GetComponentsInChildren<SkinnedMeshRenderer>())
            {
                Object.DestroyImmediate(smr.sharedMesh, true);
                Object.DestroyImmediate(smr.gameObject);
            }

            string fileName = Path.GetFileNameWithoutExtension(assetPath);
            if (!string.IsNullOrEmpty(fileName))
            {
                string[] split = fileName.Split('@');
                if (split.Length > 0)
                {
                    string fbxRoot = assetPath.Substring(0,
                        assetPath.LastIndexOf(XDirectory.Animations.ToString()));

                    string fbxFile = Path.ChangeExtension(Path.Combine(fbxRoot, split[0]), XDirectory.Fbx.ToString());
                    if (File.Exists(fbxFile))
                    {
                        Animator avatarSource = AssetDatabase.LoadAssetAtPath<Animator>(fbxFile);
                        if (avatarSource)
                        {
                            mi.sourceAvatar = avatarSource.avatar;

                            mi.animationType = importAnimationType;
                            mi.skinWeights = ModelImporterSkinWeights.Standard;
                            mi.avatarSetup = ModelImporterAvatarSetup.CopyFromOther;
                        }

                        AvatarMask avatarMask = AssetDatabase.LoadAssetAtPath<AvatarMask>(Path.ChangeExtension(fbxFile, 
                            XDirectory.Mask.ToString().ToLower()));

                        ModelImporterClipAnimation[] clipAni = new ModelImporterClipAnimation[mi.defaultClipAnimations.Length];
                        for (int i = 0; i < clipAni.Length; i++)
                        {
                            clipAni[i] = new ModelImporterClipAnimation();
                            clipAni[i] = mi.defaultClipAnimations[i];
                            clipAni[i].maskType = ClipAnimationMaskType.CopyFromOther;
                            clipAni[i].maskSource = avatarMask;
                            clipAni[i].lockRootRotation = true;
                            clipAni[i].keepOriginalOrientation = true;
                            clipAni[i].lockRootPositionXZ = true;
                            clipAni[i].keepOriginalPositionXZ = true;
                            clipAni[i].lockRootHeightY = true;
                            clipAni[i].keepOriginalPositionY = true;
                            clipAni[i].loopTime = IsLoopAnimation(split[1]);
                        }

                        mi.clipAnimations = clipAni;
                        mi.SaveAndReimport();
                    }
                }
            }
        }
        else
        {
            Animator animator = go.GetComponent<Animator>();
            if (animator)
                animator.applyRootMotion = false;

            mi.animationType = importAnimationType;
            mi.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel;

            XEditorCoroutineRunner.StartEditorCoroutine(OnGenerateModelPrefab(go, importAnimationType, useMeshCollider, copyToResources));
        }

        return true;
    }

    void OnPostprocessModel(GameObject go)
    {
        ModelImporter mi = (ModelImporter)assetImporter;
        if (mi.sourceAvatar && (mi.animationType == ModelImporterAnimationType.Human || mi.animationType == ModelImporterAnimationType.Generic))
        {
            return;
        }

        if (assetPath.Contains(XDirectory.Humanoids.ToString()))
        {
            PostprocessModels(go, ModelImporterAnimationType.Human, false, false);
        }
        else if (assetPath.Contains(XDirectory.Generics.ToString()))
        {
            PostprocessModels(go, ModelImporterAnimationType.Generic, false, false);
        }
        else if (assetPath.Contains(XDirectory.Maps.ToString()))
        {
            PostprocessModels(go, ModelImporterAnimationType.Generic, true, true);
        }
    }

}
